#小白策略之印钞机策略

import pandas as pd
import Core.Gadget as Gadget
import Core.MongoDB as MongoDB
import numpy as np
import Core.IO as IO
import datetime
import math


def StockList():
    trades = database.find("Instruments", "Stock")
    symbols = []
    for trade in trades:
        symbol = trade["Symbol"]
        symbols.append(symbol)
    return symbols

def Top_stock_list(datetime1, no_of_stocks,n):
    trades = database.find("Instruments", "Stock")
    symbols = []
    for trade in trades:
        if trade["DateTime2"] < Gadget.ToUTCDateTime(datetime1):
            continue
        symbol = trade["Symbol"]
        symbols.append(symbol)

    datetime_cal = datetime1
    datetime1 = str(datetime1)+".000"
    df = pd.DataFrame(columns=('Symbol', "Dividend", "Cash","GrossProfitMargin","NetProfitMargin","Order"))  # 生成空的pandas表
    i = 0
    for symbol in symbols:

        #datetime_before = datetime_cal - datetime.timedelta(days=32)
        #factors_Dividend = database.find("Factor", "Dividend", datetime_before, datetime_cal, query={"Symbol": symbol})
        #if len(factors_Dividend) ==0:
            #continue
        #dividend = factors_Dividend[-1]["AccumulatedDividend"]
        fundamentals = database.find("Fundamental", symbol + "_Fundamental",query={"ReportDate": datetime1})#CashEquivalents
        if len(fundamentals) == 0:
            continue
        if "CashEquivalents" not in fundamentals[0]["Values"]:
            continue
        cash = fundamentals[0]["Values"]["CashEquivalents"]
        if "PayDividend" not in fundamentals[0]["Values"]:
            continue
        dividend = fundamentals[0]["Values"]["PayDividend"]
        if "COGS" not in fundamentals[0]["Values"]:
            continue
        cogs = fundamentals[0]["Values"]["COGS"]
        if "Sales" not in fundamentals[0]["Values"]:
            continue
        sales = fundamentals[0]["Values"]["Sales"]
        if "NetIncome1" not in fundamentals[0]["Values"]:
            continue
        netincome = fundamentals[0]["Values"]["NetIncome1"]

        if sales == 0:
            continue
        if "GrossProfit" not in fundamentals[0]["Values"]:
            continue

        grossprofit = fundamentals[0]["Values"]["GrossProfit"]
        GrossProfitMargin = grossprofit/sales
        NetProfitMargin = netincome/sales
        df.loc[i] = [symbol, dividend,cash,GrossProfitMargin,NetProfitMargin, None]
        i += 1
        #print(symbol,i)
        #print(symbol, dividend, cash, GrossProfitMargin, NetProfitMargin)

    debug = 1

    df_order_by_Dividend = df.sort_values(by=["Dividend"], ascending=False)
    for i in range(len(df_order_by_Dividend)):
        df_order_by_Dividend.iloc[i, 5] = i
    df_order_by_Cash = df.sort_values(by=["Cash"], ascending=False)  # 从大到小排序
    for i in range(len(df_order_by_Cash)):
        df_order_by_Cash.iloc[i, 5] = i
    for i in range(len(df)):
        df.loc[i, 'Order'] = df_order_by_Dividend.loc[i, "Order"] + df_order_by_Cash.loc[i, "Order"]
    df_order_by_Order = df.sort_values(by=["Order"])

    top_stocks = df_order_by_Order.loc[df_order_by_Order['Order'] <= no_of_stocks]  # 索引需要注意：pandas前闭后开，包括前不包括后
    df_order_by_GPM = top_stocks.sort_values(by=["GrossProfitMargin"], ascending=False)
    qualified_stocks = df_order_by_GPM.iloc[0:n,0]
    qualified_stocks = np.array(qualified_stocks)  # np.ndarray()

    qualified_stocks = qualified_stocks.tolist()  # list
    return qualified_stocks

def Backtest(dates, no_of_stocks,n):
    net = 1
    print(dates[0],net)
    for i in range(len(dates)-1):
        stock_list = Top_stock_list(dates[i], no_of_stocks,n)
        return_of_stock = 0
        for j in range(len(stock_list)):
            symbol = stock_list[j]
            quotes = database.find("Quote", symbol + "_Time_86400_Bar", dates[i] + datetime.timedelta(days=60), dates[i+1] + datetime.timedelta(days=60))
            if len(quotes) < 2:
                continue
            quote_sell = quotes[-1]
            quote_buy = quotes[0]
            sellprice = quote_sell["Close"]/quote_sell["AdjFactor"]
            buyprice = quote_buy["Close"]/quote_buy["AdjFactor"]

            return_of_stock += (sellprice - buyprice)/buyprice
        net = net * (1 + return_of_stock/len(stock_list))
        print(dates[i+1],net)



from Core.Config import Config
config = Config()
database = config.DataBase()
datetime1 = datetime.datetime(2006, 5, 2)
datetime1 = Gadget.ToUTCDateTime(datetime1)
datetime2 = datetime.datetime(2018, 11, 21)
datetime2 = Gadget.ToUTCDateTime(datetime2)
dates = Gadget.GenerateReportDates(datetime1,datetime2)
initial = 1000000
slip = 0.01
cost = 0.0005
#StockAnalyse(dates, 20, initial , slip = 0.01 , cost = 0.0005 , trade_detail = True ,soha = True ) #更新市场因子，价值因子，和公司规模因子，需要手动输入至fama1文件里
#Top_stock_list(dates[-1], 400, 20)#现金分红与账上现金都在前200的公司，毛利率排名前20的公司
Backtest(dates, 400, 20)